/*
 * Copyright (C) 2013 AndXmppSDK Project <hljdrl@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.drl.xmpp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.drl.xmpp.impl.ChatFileTransferListener;
import org.drl.xmpp.impl.HTalkConnectionListener;
import org.drl.xmpp.impl.TalkLoginStateListener.TalkLoginState;
import org.drl.xmpp.impl.VCardListener;
import org.drl.xmpp.packet.LastExtension;
import org.drl.xmpp.packet.PingExtension;
import org.drl.xmpp.util.Logcat;
import org.drl.xmpp.util.StringHelper;
import org.drl.xmpp.util.StringUtils2;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ChatStateManager;
import org.jivesoftware.smackx.OfflineMessageManager;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.packet.ChatStateExtension;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.provider.DelayInfoProvider;
import org.jivesoftware.smackx.provider.DiscoverInfoProvider;
import org.jivesoftware.smackx.provider.DiscoverItemsProvider;
import org.jivesoftware.smackx.pubsub.provider.EventProvider;
import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
import org.jivesoftware.smackx.pubsub.provider.ItemsProvider;
import org.jivesoftware.smackx.pubsub.provider.PubSubProvider;

import android.content.Context;
import android.util.Log;

/**
 * @author hljdrl@gmail.com
 * 
 */
public class TalkFactory extends TalkClient {

	private RosterManager mRosterManager;
	private SeachManager mSeachManager;
	private TChatManager mTChatManager;
	private PresenceManager mPresenceManager;
	private VCardManager mVCardManager;
	//
	private ChatStateManager mChatStateManager;
	/**
	 * 自己的登录状态
	 * */
	private Presence currentPresence;

	private String XMPP_RESOURCE_NAME = "AndXmppSDK";

	/**
	 * @param ctx
	 */
	public TalkFactory(Context ctx) {
		super(ctx);
		//
		currentPresence = new Presence(Presence.Type.available, "在线", 1,
				Presence.Mode.available);
		//
		configure(ProviderManager.getInstance());
	}

	private void configure(ProviderManager pm) {
		// Service Discovery # Items
		pm.addIQProvider("query", "http://jabber.org/protocol/disco#items",
				new DiscoverItemsProvider());
		// Service Discovery # Info
		pm.addIQProvider("query", "http://jabber.org/protocol/disco#info",
				new DiscoverInfoProvider());
		//
		pm.addExtensionProvider("delay", "urn:xmpp:delay",
				new DelayInfoProvider());

		// Service Discovery # Items
		pm.addIQProvider("query", "http://jabber.org/protocol/disco#items",
				new DiscoverItemsProvider());
		// Service Discovery # Info
		pm.addIQProvider("query", "http://jabber.org/protocol/disco#info",
				new DiscoverInfoProvider());

		//
		// Chat State
		ChatStateExtension.Provider chatState = new ChatStateExtension.Provider();
		pm.addExtensionProvider("active",
				"http://jabber.org/protocol/chatstates", chatState);
		pm.addExtensionProvider("composing",
				"http://jabber.org/protocol/chatstates", chatState);
		pm.addExtensionProvider("paused",
				"http://jabber.org/protocol/chatstates", chatState);
		pm.addExtensionProvider("inactive",
				"http://jabber.org/protocol/chatstates", chatState);
		pm.addExtensionProvider("gone",
				"http://jabber.org/protocol/chatstates", chatState);

		// capabilities
		// pm.addExtensionProvider("c", "http://jabber.org/protocol/caps", new
		// CapsProvider());
		// Pubsub
		pm.addIQProvider("pubsub", "http://jabber.org/protocol/pubsub",
				new PubSubProvider());
		pm.addExtensionProvider("items", "http://jabber.org/protocol/pubsub",
				new ItemsProvider());
		pm.addExtensionProvider("items", "http://jabber.org/protocol/pubsub",
				new ItemsProvider());
		pm.addExtensionProvider("item", "http://jabber.org/protocol/pubsub",
				new ItemProvider());

		pm.addExtensionProvider("items",
				"http://jabber.org/protocol/pubsub#event", new ItemsProvider());
		pm.addExtensionProvider("item",
				"http://jabber.org/protocol/pubsub#event", new ItemProvider());
		pm.addExtensionProvider("event",
				"http://jabber.org/protocol/pubsub#event", new EventProvider());
	}

	private void initFeatures() {
		ServiceDiscoveryManager.setIdentityName("HealthPlatform");
		ServiceDiscoveryManager.setIdentityType("Android-Phone");
		ServiceDiscoveryManager sdm = ServiceDiscoveryManager
				.getInstanceFor(getConnection());
		if (sdm == null)
			sdm = new ServiceDiscoveryManager(getConnection());

		sdm.addFeature("http://jabber.org/protocol/disco#info");
		// nikita: must be uncommented when the feature will be enabled
		// sdm.addFeature("jabber:iq:privacy");
		sdm.addFeature("http://jabber.org/protocol/caps");
		sdm.addFeature("urn:xmpp:avatar:metadata");
		sdm.addFeature("urn:xmpp:avatar:metadata+notify");
		sdm.addFeature("urn:xmpp:avatar:data");
		sdm.addFeature("http://jabber.org/protocol/nick");
		sdm.addFeature("http://jabber.org/protocol/nick+notify");
		sdm.addFeature(PingExtension.NAMESPACE);
		sdm.addFeature(LastExtension.NAMESPACE);

		mChatStateManager = ChatStateManager.getInstance(getConnection());
	}

	private void discoverServerFeatures() {
		try {
			ServiceDiscoveryManager sdm = ServiceDiscoveryManager
					.getInstanceFor(getConnection());
			DiscoverInfo info = sdm.discoverInfo(getConnection()
					.getServiceName());
			Iterator<DiscoverInfo.Identity> it = info.getIdentities();
			while (it.hasNext()) {
				DiscoverInfo.Identity identity = it.next();
				String type = identity.getType();
				String cate = identity.getCategory();
				if ("pubsub".equals(cate) && "pep".equals(type)) {
					// initPEP();
				}
			}
		} catch (XMPPException e) {
			Log.w(TAG, "Unable to discover server features", e);
		} catch (Exception ex) {
			System.gc();
		}

	}

	// private PacketFilter mEventPacketFilter = new PacketExtensionFilter
	// ("event", "http://jabber.org/protocol/pubsub#event");
	// private EventPacketListener mEventPacketListener ;
	// private void initPEP() {
	// mEventPacketListener = new EventPacketListener(this);
	// getConnection().addPacketListener(mEventPacketListener,
	// mEventPacketFilter);
	// mPubSubManager = new PubSubManager(getConnection());
	// }
	@Override
	public final TPresence getTPresence() {
		return new TPresence(currentPresence);
	}

	@Override
	public final TChatManager getChatManager() {
		return mTChatManager;
	}

	@Override
	public final RosterManager getRosterManager() {
		return mRosterManager;
	}

	@Override
	public final PresenceManager getPresenceManager() {
		return mPresenceManager;
	}

	@Override
	public final VCardManager getVCardManager() {
		return mVCardManager;
	}

	@Override
	public final SeachManager getSeachManager() {
		return mSeachManager;
	}

	@Override
	public final void connectAsync() {
		if (isAuthentificated()) {
			return;
		}
		new Thread() {
			@Override
			public void run() {
				connectSync();
			}
		}.start();
	}

	@Override
	public final boolean connectSync() {
		if (connect())
			return login();
		return false;
	}

	List<ConnectionListener> mRemoteConnListeners;
	List<VCardListener> iVCardlisteners;
	HTalkConnectionListener mHTalkConnectionListener;
	String errorMessage;
	int errorCode;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.drl.xmpp.TalkClient#connect()
	 */
	@Override
	public final boolean connect() {
		Logcat.d("connect()");
		if (isConnected()) {
			return true;
		} else {
			try {
				setLoginState(TalkLoginState.CONNECT, "正在连接...");
				ConnectionConfiguration config = null;
				config = new ConnectionConfiguration(mHost,mPort);

				config.setReconnectionAllowed(true);
				config.setRosterLoadedAtLogin(true);
				config.setSendPresence(false);
				config.setSASLAuthenticationEnabled(true);
				config.setSecurityMode(SecurityMode.disabled);
				//
				XMPPConnection connection = new XMPPConnection(config);
				setLoginState(TalkLoginState.CONNECTED, "连接服务器中...");
				connection.connect();
				setXMPPConnection(connection);

				mRemoteConnListeners = new ArrayList<ConnectionListener>();
				iVCardlisteners = new ArrayList<VCardListener>();

				mHTalkConnectionListener = new HTalkConnectionListener();
				getConnection().addConnectionListener(mHTalkConnectionListener);
				return true;
			} catch (Exception e) {
				try {

					if (e instanceof XMPPException) {
						XMPPException xe = (XMPPException) e;
						final XMPPError error = xe.getXMPPError();
						int eCode;
						//
						if (error != null) {
							eCode = error.getCode();
							errorMessage = error.getMessage();
							errorCode = eCode;
						}
					}
				} catch (NullPointerException e2) {
					e2.printStackTrace();
				}

			}
		}
		return false;
	}

	/**
	 * TODO: 用一句话描述这个方法的作用
	 * 
	 */
	private final void initPacketListener() {
		// mPingListener = new PingAndLastPacketListener(this);
		// mUserPacketsListener = new UserPacketsListener(this, mContext);
		// mPresenceListener = new PresenceListener(mContext,this);
		// OrFilter filter2 = new OrFilter(new UserSafetyInfoFilter(),new
		// UserAccountFilter());
		// OrFilter filter3 = new OrFilter(new UserVCardFilter(), filter2);
		// mPushMessagerListener = new PushMessagerListener(mContext);
		// mTrendPacketListener = new TrendPacketListener(mContext, this);
		// mVCardMinPacketListener = new VCardMinPacketListener(mContext, this);
		// mSysRosterPacketListener = new SysRosterPacketListener(mContext,
		// this);
		// PacketFilter filter = new PacketTypeFilter(PingExtension.class);
		// getConnection().addPacketListener(mPingListener, filter);
		// getConnection().addPacketListener(mPresenceListener,
		// mSubscribePacketFilter);
		// getConnection().addPacketListener(mSysRosterPacketListener,
		// mSysRosterFilter);
		// getConnection().addPacketListener(mUserPacketsListener, filter3);
		// getConnection().addPacketListener(mPushMessagerListener, new
		// PushMessagerFilter());
		// getConnection().addPacketListener(mTrendPacketListener,new
		// TrendFilter());
		// getConnection().addPacketListener(mVCardMinPacketListener,new
		// VCardFilter());
	}

	/**
	 * 初始化-广播消息接受
	 * */
	private final void initBDT() {
		// broadcast = new BroadcastListener(this, mContext);
		// PacketFilter serverFilter = new PacketTypeFilter(Message.class);
		// getConnection().addPacketListener(broadcast, serverFilter);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.drl.xmpp.TalkClient#login()
	 */
	@Override
	public final boolean login() {
		Logcat.d("login()");
		if (!isConnected()) {
			return false;
		} else if (isAuthentificated()) {
			return true;
		}
		this.initFeatures();
		try {
			// if(!HttpHelper.isNetWorkAvailable(mContext)){
			// return false;
			// }
			initPacketListener();
			initBDT();
			//
			setLoginState(TalkLoginState.LOGING, "登录中...");
			getConnection().login(getUserInfo().getUserName(),
					getUserInfo().getPassword());
			mRosterManager = new RosterManager(this);
			mUserInfo.setJid(getConnection().getUser());
			// setServerAddress(getConnection().getServiceName());
			// getConnection().sendPacket(currentPresence);
			// if(mUserInfo==null){
			// return false;
			// }
			// setServerAddress(StringUtils.parseBareAddress(connection.getUser()));
			// //
			// discoverServerFeatures();
			// mRosterManager = new RosterManager(this);
			// mVCardManager = new VCardManager(this);
			// initLogin();
			// initOMM();
			setLoginState(TalkLoginState.LOGIN_SUCC, "登录成功!");
			initLogin();
			return true;
		} catch (XMPPException e) {
			if (e instanceof XMPPException) {
				XMPPException xe = (XMPPException) e;
				final XMPPError error = xe.getXMPPError();
				int eCode;
				//
				if (error != null) {
					eCode = error.getCode();
					errorMessage = error.getMessage();
					errorCode = eCode;
				}
			}
			e.printStackTrace();
			setLoginState(TalkLoginState.LOGIN_FAIL,
					"登录失败!\n" + StringHelper.exceptionToString(e));
			return false;
		} catch (NullPointerException ne) {
			ne.printStackTrace();
			setLoginState(TalkLoginState.LOGIN_FAIL,
					"登录失败!\n" + StringHelper.exceptionToString(ne));
			return false;
		} catch (Exception ex) {
			ex.printStackTrace();
			setLoginState(TalkLoginState.LOGIN_FAIL,
					"登录失败!\n" + StringHelper.exceptionToString(ex));
			return false;
		}
	}

	/**
	 * TODO: 登录成功以后，数据加载
	 * 
	 */
	private final void initLogin() {
				try {
					mPresenceManager = new PresenceManager(TalkFactory.this);
					initFTM();
					mTChatManager = new TChatManager(TalkFactory.this,
							getConnection().getChatManager());
					mVCardManager = new VCardManager(TalkFactory.this);
					getConnection().sendPacket(currentPresence);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
	}

	private FileTransferManager transferManager;
	private FileTransferListener mFileTransferListener;

	/**
	 * 添加文件监听器
	 * */
	private final void initFTM() {
		// 添加文件监听器
		if (transferManager == null) {
			transferManager = new FileTransferManager(getConnection());
		}
		if (mFileTransferListener == null) {
			mFileTransferListener = new ChatFileTransferListener(this);
		}
		transferManager.addFileTransferListener(mFileTransferListener);
	}

	/**
	 * OfflineMessageManager-离线消息获取
	 * */
	private final void initOMM() {
		OfflineMessageManager offlineManager = new OfflineMessageManager(
				getConnection());
		try {

			Iterator<org.jivesoftware.smack.packet.Message> it = offlineManager
					.getMessages();
			int count = offlineManager.getMessageCount();
			Map<String, Message> offlineMsgMap = new HashMap<String, Message>();
			List<String> keys = new ArrayList<String>();
			while (it.hasNext()) {
				Message message = it.next();
				String key = StringUtils2.formateDataOfflineMessageKey(message);
				offlineMsgMap.put(key, message);
			}
			for (String k : keys) {
				Message message = offlineMsgMap.get(k);
				TMessage $message = new TMessage(message);
			}
			offlineManager.deleteMessages();
			keys.clear();
			offlineMsgMap.clear();
			keys = null;
			offlineMsgMap = null;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@Override
	public void disconnect() {

		if (isConnected()) {
			getConnection().disconnect();
			System.gc();
		}

	}

	@Override
	public final void changeStatus(TPresence status) {
		if (status != null) {
			currentPresence.setType(TPresence.getPresenceTypeFrom(status
					.getType()));
			currentPresence.setMode(PresenceStatus
					.getPresenceModeFromStatus(status.getStatus()));
			currentPresence.setStatus(status.getStatusText());
			getConnection().sendPacket(currentPresence);
		}
	}

	@Override
	final boolean setAvatar(String fileName) {
		return false;
	}

	@Override
	final String getConnectionID() {
		return null;
	}

	@Override
	final public void sendFile(String user, String fileName, String mDescript) {

	}

}
